﻿#ifndef _CSTRING_UTILS_H_
#define _CSTRING_UTILS_H_
#include<iostream>
#include <assert.h>

/*
 * @brief 字符串拼接函数
 * @return 返回dest字符串起始地址
 * @description 将参数src字符串复制到参数dest所指的字符串尾部
 *	            dest与src所指的内存空间不能重叠，且dest要有足够的空间来容纳要复制的字符串
 */
char *strcat(char *dest, const char *src)
{
	assert(dest != NULL && src != NULL);
	char *result = dest;
	while (*dest != '\0') ++dest;
	while ((*dest++ = *src++) != '\0');
	return result;
}



/*
 * @brief 将n个字符追加到字符串的结尾
 * @return 返回dest字符串起始地址
 * @description 将字符串src的开头拷贝n个字符到dest字符串尾部，dest要有足够的空间来容纳要拷贝的字符串
 */
char *strncat(char *dest, const char *src, size_t n)
{
	assert(dest != NULL && src != NULL);
	char *result = dest;
	while (*dest != '\0')++dest;
	while (n-- && (*dest++ = *src++) != '\0');
	*dest = '\0';
	return result;
}


/*
 * @brief 将参数src字符串拷贝至参数dest所指的地址
 * @return 返回参数dest的字符串起始地址
 * @description 如果参数dest所指的内存空间不够大，可能会造成缓冲溢出的错误情况
 */
char *strcpy(char *dest, const char *src)
{
	assert(dest != NULL && src != NULL);
	char *result = dest;
	while ((*dest++ = *src++) != '\0');
	return result;
}

/*
 * @brief 将字符串src前n个字符拷贝到字符串dest
 * @return 返回参数dest的字符串起始地址
 * @description src和dest所指的内存区域不能重叠，dest必须有足够的空间放置n个字符
 */
char *strncpy(char *dest, const char *src, size_t n)
{
	assert(dest != NULL && src != NULL);
	char *result = dest;
	while (n-- && (*dest++ = *src++) != '\0');
	return result;
}

 
/*
 * @brief 字符串比较
 * @return 若参数s1和s2字符串相同则返回0，s1若大于s2则返回大于0的值，s1若小于s2则返回小于0的值
 * @description strcmp区分大小写比较，stricmp函数不区分大小写进行字符串比较
 */
int strcmp(const char *s1, const char *s2)
{
	assert(s1 != NULL && s2 != NULL);
	while (s1 && s2 && (s1 == s2)) {
		++s1;
		++s2;
	}
	return (*s1 - *s2);
}

/*
 * @brief 计算指定的字符串s的长度，不包括结束字符'\0'
 * @return 返回字符串s的字符数
 * @description 计算字符串的实际长度，到第一个'\0'结束；
 *	         如果你只定义没有给它赋初值，这个结果是不定的，它会从首地址一直找下去，直到遇到'\0'停止；
 *	         sizeof返回的是变量声明后所占的内存数，不是实际长度，此外sizeof不是函数，仅仅是一个操作符，strlen()是函数；
 */
size_t strlen(const char *s)
{
	assert(s != NULL);
	size_t len = 0;
	while (*s++ != '\0')
		++len;
	return len;
}


/*
 * @brief 字符串逆序
 * @return  返回逆序后dest字符串起始地址
 * @description 
 */
char* reverse(const char *src)
{
	assert(nullptr != src);
	char *dest = new char[strlen(src) + 1];
	strcpy(dest, src);

	const int Len = strlen(dest);
	char c = 0;
	for (int i = 0; i < Len / 2; ++i)
	{
		c = dest[i];
		dest[i] = dest[Len - i - 1];
		dest[Len - i - 1] = c;
	}
	return dest;
}


/*
 * @brief 把字符串中的小写字母替换为大写
 * @return  返回换为大写后dest字符串起始地址
 * @description
 */
char* toUpper(const char *src)
{
	assert(nullptr != src);
	char *dest = new char[strlen(src) + 1];
	strcpy(dest, src);

	for (char *i = dest; *i != '\0'; ++i)
	{
		if (*i < 'a' || *i > 'z')
		{
			continue;
		}
		*i -= 'a' - 'A';
	}
	return dest;
}

/*
 * @brief 把字符串中的大写字母替换为小写
 * @return  返回换为小写后dest字符串起始地址
 * @description
 */
char* toLower(const char *src)
{
	assert(nullptr != src);
	char *dest = new char[strlen(src) + 1];
	strcpy(dest, src);

	for (char *i = dest; *i != '\0'; ++i)
	{
		if (*i < 'A' || *i > 'Z')
		{
			continue;
		}
		*i += 'a' - 'A';
	}
	return dest;
}


/*
 * @brief 查找子串在字符串中首次出现的位置
 * @return
 * @description
 */
char* strstr(char *str, char * substr)
{
	assert(str != NULL && substr != NULL);
	char *s = str;
	char *t = substr;
	for (; *str != '\0'; str++) {
		for (s = str, t = substr; *t != '\0' && *s == *t; ++s, ++t);
		if (*t == '\0')return (char*)str;
	}
	return NULL;
}

/*
 * @brief 在一个字符串中查找给定字符的第一个匹配之处
 * @return 如果找到指定的字符则返回该字符所在地址，否则返回NULL
 * @description 返回的地址是字符串在内存中随机分配的地址再加上你所搜索的字符在字符串的位置
 *	         字符串str的结束标志‘\0’也会被纳入检索范围，所以str的最后一个字符也可以被定位
 *	         如果希望查找某字符在字符串中最后一次出现的位置，可以使用 strrchr() 函数
 */
char* strchr(const char *str, int c)
{
	assert(str != NULL);
	for (; *str != c; str++) {
		if (*str == '\0')
			return NULL;
	}
	return (char*)str;
}


/*
 * @brief 字符串分割
 * @return 返回下一个分割后的字符串指针，如果已无从分割则返回NULL
 * @description 当strtok()在参数s的字符串中发现到参数delim的分割字符时则会将该字符改为'\0'字符
 *	            在第一次调用时，strtok()必须赋予参数s字符串，往后的调用则将参数s设置成NULL
 */
char *strtok_r(char *s, const char *delim, char **save_ptr) {
	char *token;
	if (s == NULL) s = *save_ptr;
	s += strspn(s, delim);
	if (*s == '\0')
		return NULL;
	token = s;
	s = strpbrk(token, delim);
	if (s == NULL)
		*save_ptr = strchr(token, '\0');
	else {
		*s = '\0';
		*save_ptr = s + 1;
	}
	return token;
}

char *strtok(char *s, const char *delim)
{
	static char *last;
	return strtok_r(s, delim, &last);
}



//1.const char* 和string 转换
//const char*转string，直接赋值
const char* pc = "it container";
std::string str = pc;

//string转const char*，利用c_str()或者data()
std::string str = "tsinghua";
const char* pc = str.c_str();
const char* pc = str.data();

//2.char*和const char*之间的转换
//const char*转char*，利用const_cast<char*>
const char* pc = "it container";
char* c = const_cast<char*>(pc);

//char*转const char*，直接赋值
char* c = (char *)"it container";
const char* pc = c;

//3. char*和string之间的转换
//char*转string，直接赋值
char* c = (char *)"it container";
std::string str = c;

//string转char*， 1. string->const char*，2. const char*->char*
std::string str = "it container";
char* c = const_cast<char*>(str.c_str());

#endif // !_CSTRING_UTILS_H_
